home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / os2 / octa209s.zip / octave-2.09 / src / octave.cc < prev    next >
C/C++ Source or Header  |  1997-05-26  |  17KB  |  644 lines

  1. /*
  2.  
  3. Copyright (C) 1996 John W. Eaton
  4.  
  5. This file is part of Octave.
  6.  
  7. Octave is free software; you can redistribute it and/or modify it
  8. under the terms of the GNU General Public License as published by the
  9. Free Software Foundation; either version 2, or (at your option) any
  10. later version.
  11.  
  12. Octave is distributed in the hope that it will be useful, but WITHOUT
  13. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14. FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  15. for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with Octave; see the file COPYING.  If not, write to the Free
  19. Software Foundation, 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  20.  
  21. */
  22.  
  23. // Born February 20, 1992.
  24.  
  25. /* Modified by Klaus Gebhardt, 1996 */
  26.  
  27. #ifdef HAVE_CONFIG_H
  28. #include <config.h>
  29. #endif
  30.  
  31. #include <cassert>
  32. #include <csignal>
  33. #include <cstdlib>
  34. #include <cstring>
  35. #include <ctime>
  36.  
  37. #include <fstream.h>
  38. #include <iostream.h>
  39. #include <strstream.h>
  40.  
  41. #ifdef HAVE_UNISTD_H
  42. #ifdef HAVE_SYS_TYPES_H
  43. #include <sys/types.h>
  44. #endif
  45. #include <unistd.h>
  46. #endif
  47.  
  48. #ifdef HAVE_PWD_H
  49. #include <pwd.h>
  50. #endif
  51.  
  52. #ifdef __EMX__
  53. #include <float.h>
  54. #include <sys/uflags.h>
  55. #endif
  56.  
  57. #include "lo-error.h"
  58. #include "str-vec.h"
  59.  
  60. #include "builtins.h"
  61. #include <defaults.h>
  62. #include "defun.h"
  63. #include "dynamic-ld.h"
  64. #include "error.h"
  65. #include "file-io.h"
  66. #include "file-ops.h"
  67. #include "help.h"
  68. #include "input.h"
  69. #include "lex.h"
  70. #include "oct-hist.h"
  71. #include "ops.h"
  72. #include "toplev.h"
  73. #include "parse.h"
  74. #include "pathsearch.h"
  75. #include "procstream.h"
  76. #include "prog-args.h"
  77. #include "sighandlers.h"
  78. #include "sysdep.h"
  79. #include "ov.h"
  80. #include "pt-misc.h"
  81. #include "pt-plot.h"
  82. #include "unwind-prot.h"
  83. #include "utils.h"
  84. #include "variables.h"
  85. #include <version.h>
  86.  
  87. #if !defined (HAVE_ATEXIT) && defined (HAVE_ON_EXIT)
  88. extern "C" int on_exit ();
  89. #define atexit on_exit
  90. #endif
  91.  
  92. // Don't redefine the variables if glibc already has.
  93. #if defined (HAVE_PROGRAM_INVOCATION_NAME) || defined (WITH_KPATHSEARCH)
  94. extern char *program_invocation_name;
  95. extern char *program_invocation_short_name;
  96. #else
  97. char *program_invocation_name;
  98. char *program_invocation_short_name;
  99. #endif
  100.  
  101. #if defined (USE_READLINE)
  102. // This is from readline's paren.c:
  103. extern int rl_blink_matching_paren;
  104. #endif
  105.  
  106. // The command-line options.
  107. static string_vector octave_argv;
  108.  
  109. // TRUE means we read ~/.octaverc and ./.octaverc.
  110. // (--norc; --no-init-file; -f)
  111. static bool read_init_files = true;
  112.  
  113. // TRUE means we read the site-wide octaverc files.
  114. // (--norc; --no-site-file; -f)
  115. static bool read_site_files = true;
  116.  
  117. // Nonzero means we don't print the usual startup message.
  118. // (--quiet; --silent; -q)
  119. static bool inhibit_startup_message = false;
  120.  
  121. // Nonzero means we turn on compatibility options.
  122. // (--traditional)
  123. static bool traditional = false;
  124.  
  125. // If nonzero, print verbose info in some cases.
  126. // (--verbose; -V)
  127. static bool verbose_flag = false;
  128.  
  129. // Usage message
  130. static const char *usage_string = 
  131.   "octave [-?VdfhiIqvx] [--debug] [--echo-commands] [--exec-path path]\n\
  132.        [--help] [--info-file file] [--info-program prog] [--interactive]\n\
  133.        [--no-init-file] [--no-line-editing] [--no-site-file] [-p path]\n\
  134.        [--path path] [--silent] [--traditional] [--verbose] [--version] [file]";
  135.  
  136. // This is here so that it's more likely that the usage message and
  137. // the real set of options will agree.  Note: the `+' must come first
  138. // to prevent getopt from permuting arguments!
  139. static const char *short_opts = "+?VdfhiIp:qvx";
  140.  
  141. // Long options.  See the comments in getopt.h for the meanings of the
  142. // fields in this structure.
  143. #define EXEC_PATH_OPTION 1
  144. #define INFO_FILE_OPTION 2
  145. #define INFO_PROG_OPTION 3
  146. #define NO_INIT_FILE_OPTION 4
  147. #define NO_LINE_EDITING_OPTION 5
  148. #define NO_SITE_FILE_OPTION 6
  149. #define TRADITIONAL_OPTION 7
  150. long_options long_opts[] =
  151.   {
  152.     { "debug",            prog_args::no_arg,       0, 'd' },
  153.     { "braindead",        prog_args::no_arg,       0, TRADITIONAL_OPTION },
  154.     { "echo-commands",    prog_args::no_arg,       0, 'x' },
  155.     { "exec-path",        prog_args::required_arg, 0, EXEC_PATH_OPTION },
  156.     { "help",             prog_args::no_arg,       0, 'h' },
  157.     { "info-file",        prog_args::required_arg, 0, INFO_FILE_OPTION },
  158.     { "info-program",     prog_args::required_arg, 0, INFO_PROG_OPTION },
  159.     { "interactive",      prog_args::no_arg,       0, 'i' },
  160.     { "no-init-file",     prog_args::no_arg,       0, NO_INIT_FILE_OPTION },
  161.     { "no-line-editing",  prog_args::no_arg,       0, NO_LINE_EDITING_OPTION },
  162.     { "no-site-file",     prog_args::no_arg,       0, NO_SITE_FILE_OPTION },
  163.     { "norc",             prog_args::no_arg,       0, 'f' },
  164.     { "path",             prog_args::required_arg, 0, 'p' },
  165.     { "quiet",            prog_args::no_arg,       0, 'q' },
  166.     { "silent",           prog_args::no_arg,       0, 'q' },
  167.     { "traditional",      prog_args::no_arg,       0, TRADITIONAL_OPTION },
  168.     { "verbose",          prog_args::no_arg,       0, 'V' },
  169.     { "version",          prog_args::no_arg,       0, 'v' },
  170.     { 0,                  0,                 0, 0 }
  171.   };
  172.  
  173. // Store the command-line options for later use.
  174.  
  175. static void
  176. intern_argv (int argc, char **argv)
  177. {
  178.   if (argc > 1)
  179.     {
  180.       // Skip program name in argv.
  181.  
  182.       octave_argv = string_vector (argv+1, argc-1);
  183.  
  184.       bind_builtin_variable ("argv", octave_argv, 1, 1, 0);
  185.       bind_builtin_variable ("__argv__", octave_argv, 1, 1, 0);
  186.     }
  187.  
  188.   bind_builtin_variable ("nargin", (double) argc-1, 1, 1, 0);
  189. }
  190.  
  191. // Initialize some global variables for later use.
  192.  
  193. static void
  194. initialize_globals (const string& name)
  195. {
  196.   // Kpathsea needs this.
  197.  
  198. #if ! defined (HAVE_PROGRAM_INVOCATION_NAME)
  199.   program_invocation_name = strsave (name.c_str ());
  200.   program_invocation_short_name = strrchr (program_invocation_name, '/');
  201.   if (! program_invocation_short_name)
  202.     program_invocation_short_name = program_invocation_name;
  203. #endif
  204.  
  205.   Vprogram_invocation_name = name;
  206.   size_t pos = Vprogram_invocation_name.rfind ('/');
  207.   Vprogram_name = (pos == NPOS)
  208.     ? Vprogram_invocation_name : Vprogram_invocation_name.substr (pos+1);
  209.  
  210.   struct passwd *entry = getpwuid (getuid ());
  211.   Vuser_name = entry ? entry->pw_name : "I have no name!";
  212.  
  213.   char hostname[256];
  214.   int status = gethostname (hostname, 255);
  215.   Vhost_name = (status < 0) ? "I have no host!" : hostname;
  216.  
  217.   char *hd = getenv ("HOME");
  218.   Vhome_directory = hd ? hd : "I have no home!";
  219.  
  220.   install_defaults ();
  221. }
  222.  
  223. static void
  224. initialize_pathsearch (void)
  225. {
  226.   // This may seem odd, but doing it this way means that we don't have
  227.   // to modify the kpathsea library...
  228.  
  229.   char *odb = getenv ("OCTAVE_DB_DIR");
  230.  
  231.   if (odb)
  232.     oct_putenv ("TEXMF", odb);
  233.   else
  234.     {
  235.       char *oh = getenv ("OCTAVE_HOME");
  236.  
  237.       if (oh)
  238.     {
  239.       int len = strlen (oh) + 12;
  240.       char *putenv_val = new char [len];
  241.       sprintf (putenv_val, "%s/lib/octave", oh);
  242.       oct_putenv ("TEXMF", putenv_val);
  243.     }
  244.       else  
  245.     oct_putenv ("TEXMF", OCTAVE_DATADIR "/octave");
  246.     }
  247. }
  248.  
  249. // Initialize by reading startup files.
  250.  
  251. static void
  252. execute_startup_files (void)
  253. {
  254.   begin_unwind_frame ("execute_startup_files");
  255.  
  256.   // XXX FIXME XXX -- need to make it possible to set this in startup
  257.   // files.
  258.  
  259.   unwind_protect_int (input_from_startup_file);
  260.  
  261.   input_from_startup_file = 1;
  262.  
  263.   int verbose = (verbose_flag && ! inhibit_startup_message);
  264.  
  265.   if (read_site_files)
  266.     {
  267.       // Execute commands from the site-wide configuration file.
  268.       // First from the file $(prefix)/lib/octave/site/m/octaverc
  269.       // (if it exists), then from the file
  270.       // $(prefix)/lib/octave/$(version)/m/octaverc (if it exists).
  271.  
  272.       parse_and_execute (Vlocal_site_defaults_file, 0, verbose);
  273.  
  274.       parse_and_execute (Vsite_defaults_file, 0, verbose);
  275.     }
  276.  
  277.   if (read_init_files)
  278.     {
  279.       // Try to execute commands from $HOME/$OCTAVE_INITFILE and
  280.       // $OCTAVE_INITFILE.  If $OCTAVE_INITFILE is not set, .octaverc
  281.       // is assumed.
  282.  
  283.       int home_rc_already_executed = 0;
  284.  
  285.       char *initfile = getenv ("OCTAVE_INITFILE");
  286.  
  287.       if (! initfile)
  288.     initfile = ".octaverc";
  289.  
  290.       string home_rc = Vhome_directory + "/" + initfile;
  291.       string local_rc = string ("./") + initfile;
  292.  
  293.       if (! Vhome_directory.empty ())
  294.     {
  295.       parse_and_execute (home_rc, 0, verbose);
  296.  
  297.       // Names alone are not enough.
  298.  
  299.       file_stat fs_home_rc (home_rc);
  300.  
  301.       if (fs_home_rc)
  302.         {
  303.           file_stat fs_dot_rc (local_rc);
  304.  
  305.           if (fs_dot_rc && fs_home_rc.ino () == fs_dot_rc.ino ())
  306.         home_rc_already_executed = 1;
  307.         }
  308.     }
  309.  
  310.       if (! home_rc_already_executed)
  311.     parse_and_execute (local_rc, 0, verbose);
  312.     }
  313.  
  314.   run_unwind_frame ("execute_startup_files");
  315. }
  316.  
  317. // Usage message with extra help.
  318.  
  319. static void
  320. verbose_usage (void)
  321. {
  322.   cout << OCTAVE_NAME_VERSION_AND_COPYRIGHT "\n\
  323. \n\
  324. Usage: octave [options]\n\
  325. \n\
  326. Options:\n\
  327. \n\
  328.   -d, --debug             Enter parser debugging mode.\n\
  329.   -x, --echo-commands     Echo commands as they are executed.\n\
  330.   --exec-path PATH        Set path for executing subprograms.\n\
  331.   -h, -?, --help          Print short help message and exit.\n\
  332.   -f, --norc              Don't read any initialization files.\n\
  333.   --info-file FILE        Use top-level info file FILE.\n\
  334.   --info-program PROGRAM  Use PROGRAM for reading info files.\n\
  335.   -i, --interactive       Force interactive behavior.\n\
  336.   -I                      Force really interactive behavior, but no pager.\n\
  337.   --no-init-file          Don't read the ~/.octaverc or .octaverc files.\n\
  338.   --no-line-editing       Don't use readline for command-line editing.\n\
  339.   --no-site-file          Don't read the site-wide octaverc file.\n\
  340.   -p PATH, --path PATH    Set initial LOADPATH to PATH.\n\
  341.   -q, --silent            Don't print message at startup.\n\
  342.   --traditional           Set compatibility variables.\n\
  343.   -V, --verbose           Enable verbose output in some cases.\n\
  344.   -v, --version           Print version number and exit.\n\
  345. \n\
  346.   FILE                    Execute commands from FILE.\n\
  347. \n\
  348. Additional information about Octave is available via the WWW at\n\
  349. http://www.che.wisc.edu/octave.\n\
  350. \n\
  351. Please report bugs to the mailing list `bug-octave@bevo.che.wisc.edu'.\n";
  352.  
  353.   exit (0);
  354. }
  355.  
  356. // Terse usage messsage.
  357.  
  358. static void
  359. usage (void)
  360. {
  361.   cerr << "usage: " << usage_string << "\n";
  362.   exit (1);
  363. }
  364.  
  365. static void
  366. print_version_and_exit (void)
  367. {
  368.   cout << OCTAVE_NAME_AND_VERSION << "\n";
  369.   exit (0);
  370. }
  371.  
  372. static void
  373. initialize_error_handlers ()
  374. {
  375.   set_liboctave_error_handler (error);
  376. }
  377.  
  378. // What happens on --traditional.
  379.  
  380. static void
  381. maximum_braindamage (void)
  382. {
  383.   bind_builtin_variable ("PS1", ">> ");
  384.   bind_builtin_variable ("PS2", "");
  385.   bind_builtin_variable ("beep_on_error", 1.0);
  386.   bind_builtin_variable ("default_eval_print_flag", 0.0);
  387.   bind_builtin_variable ("default_save_format", "mat-binary");
  388.   bind_builtin_variable ("define_all_return_values", 1.0);
  389.   bind_builtin_variable ("do_fortran_indexing", 1.0);
  390.   bind_builtin_variable ("empty_list_elements_ok", 1.0);
  391.   bind_builtin_variable ("implicit_str_to_num_ok", 1.0);
  392.   bind_builtin_variable ("ok_to_lose_imaginary_part", 1.0);
  393.   bind_builtin_variable ("page_screen_output", 0.0);
  394.   bind_builtin_variable ("prefer_column_vectors", 0.0);
  395.   bind_builtin_variable ("prefer_zero_one_indexing", 1.0);
  396.   bind_builtin_variable ("print_empty_dimensions", 0.0);
  397.   bind_builtin_variable ("treat_neg_dim_as_zero", 1.0);
  398.   bind_builtin_variable ("warn_function_name_clash", 0.0);
  399.   bind_builtin_variable ("whitespace_in_literal_matrix", "traditional");
  400. }
  401.  
  402. // You guessed it.
  403.  
  404. int
  405. main (int argc, char **argv)
  406. {
  407.   // The order of these calls is important.  The call to
  408.   // initialize_globals must come before install_builtins because
  409.   // default variable values must be available for the varaibles to be
  410.   // installed, and the call to install_builtins must come before the
  411.   // options are processed because some command line options override
  412.   // defaults by calling bind_builtin_variable.
  413.  
  414.   sysdep_init ();
  415.  
  416.   initialize_error_handlers ();
  417.  
  418.   initialize_globals (argv[0]);
  419.  
  420.   initialize_pathsearch ();
  421.  
  422.   install_signal_handlers ();
  423.  
  424.   initialize_file_io ();
  425.  
  426.   initialize_symbol_tables ();
  427.  
  428.   install_types ();
  429.  
  430.   install_ops ();
  431.  
  432.   install_builtins ();
  433.  
  434.   prog_args args (argc, argv, short_opts, long_opts);
  435.  
  436.   int optc;
  437.   while ((optc = args.getopt ()) != EOF)
  438.     {
  439.       switch (optc)
  440.     {
  441.     case 'V':
  442.       verbose_flag = true;
  443.       break;
  444.  
  445.     case 'd':
  446.       yydebug++;
  447.       break;
  448.  
  449.     case 'f':
  450.       read_init_files = false;
  451.       read_site_files = false;
  452.       break;
  453.  
  454.     case 'h':
  455.     case '?':
  456.       verbose_usage ();
  457.       break;
  458.  
  459.     case 'i':
  460.       forced_interactive = 1;
  461.       break;
  462.  
  463.     case 'I':
  464.       really_forced_interactive = 1;
  465.       break;
  466.  
  467.     case 'p':
  468.       if (args.optarg ())
  469.         bind_builtin_variable ("LOADPATH", args.optarg ());
  470.       break;
  471.  
  472.     case 'q':
  473.       inhibit_startup_message = true;
  474.       break;
  475.  
  476.     case 'x':
  477.       {
  478.         double tmp = (ECHO_SCRIPTS | ECHO_FUNCTIONS | ECHO_CMD_LINE);
  479.         bind_builtin_variable ("echo_executing_commands", tmp);
  480.       }
  481.       break;
  482.  
  483.     case 'v':
  484.       print_version_and_exit ();
  485.       break;
  486.  
  487.     case EXEC_PATH_OPTION:
  488.       if (args.optarg ())
  489.         bind_builtin_variable ("EXEC_PATH", args.optarg ());
  490.       break;
  491.  
  492.     case INFO_FILE_OPTION:
  493.       if (args.optarg ())
  494.         bind_builtin_variable ("INFO_FILE", args.optarg ());
  495.       break;
  496.  
  497.     case INFO_PROG_OPTION:
  498.       if (args.optarg ())
  499.         bind_builtin_variable ("INFO_PROGRAM", args.optarg ());
  500.       break;
  501.  
  502.     case NO_INIT_FILE_OPTION:
  503.       read_init_files = false;
  504.       break;
  505.  
  506.     case NO_LINE_EDITING_OPTION:
  507.       using_readline = false;
  508.       break;
  509.  
  510.     case NO_SITE_FILE_OPTION:
  511.       read_site_files = 0;
  512.       break;
  513.  
  514.     case TRADITIONAL_OPTION:
  515.       traditional = true;
  516.       break;
  517.  
  518.     default:
  519.       usage ();
  520.       break;
  521.     }
  522.     }
  523.  
  524. #if defined (HAVE_ATEXIT) || defined (HAVE_ON_EXIT)
  525.   // Make sure we clean up when we exit.  Also allow users to register
  526.   // functions.  If we don't have atexit or on_exit, we're going to
  527.   // leave some junk files around if we exit abnormally.
  528.  
  529.   atexit (do_octave_atexit);
  530.  
  531.   atexit (cleanup_tmp_files);
  532. #endif
  533.  
  534.   // These can come after command line args since none of them set any
  535.   // defaults that might be changed by command line options.
  536.  
  537.   initialize_readline ();
  538.  
  539.   init_dynamic_linker ();
  540.  
  541.   if (! inhibit_startup_message)
  542.     cout << OCTAVE_STARTUP_MESSAGE "\n" << endl;
  543.  
  544.   if (traditional)
  545.     maximum_braindamage ();
  546.  
  547.   execute_startup_files ();
  548.  
  549.   octave_command_history.read (false);
  550.  
  551.   if (! inhibit_startup_message && reading_startup_message_printed)
  552.     cout << endl;
  553.  
  554. #if defined (__EMX__)
  555.   _control87 (EM_INVALID | EM_DENORMAL | EM_ZERODIVIDE | EM_OVERFLOW |
  556.           EM_UNDERFLOW | EM_INEXACT, MCW_EM);
  557.  
  558.   _uflags (_UF_SBRK_MODEL, _UF_SBRK_ARBITRARY);
  559. #endif
  560.  
  561.   // Avoid counting commands executed from startup files.
  562.  
  563.   current_command_number = 1;
  564.  
  565.   // If there is an extra argument, see if it names a file to read.
  566.   // Additional arguments are taken as command line options for the
  567.   // script.
  568.  
  569.   int last_arg_idx = args.optind ();
  570.   int remaining_args = argc - last_arg_idx;
  571.   if (remaining_args > 0)
  572.     {
  573.       reading_script_file = 1;
  574.       curr_fcn_file_name = argv[last_arg_idx];
  575.       curr_fcn_file_full_name = curr_fcn_file_name;
  576.  
  577.       FILE *infile = get_input_from_file (curr_fcn_file_name);
  578.  
  579.       if (infile)
  580.     {
  581.       input_from_command_line_file = 1;
  582.  
  583.       bind_builtin_variable ("program_invocation_name",
  584.                  curr_fcn_file_name);
  585.  
  586.       size_t pos = curr_fcn_file_name.rfind ('/');
  587.  
  588.       string tmp = (pos != NPOS)
  589.         ? curr_fcn_file_name.substr (pos+1) : curr_fcn_file_name;
  590.  
  591.       bind_builtin_variable ("program_name", tmp);
  592.  
  593.       intern_argv (remaining_args, argv+last_arg_idx);
  594.  
  595.       rl_blink_matching_paren = 0;
  596.       switch_to_buffer (create_buffer (infile));
  597.     }
  598.       else
  599.     clean_up_and_exit (1);
  600.     }
  601.   else
  602.     {
  603.       // Is input coming from a terminal?  If so, we are probably
  604.       // interactive.
  605.  
  606.       interactive = (isatty (fileno (stdin)) && isatty (fileno (stdout)));
  607.  
  608.       intern_argv (argc, argv);
  609.  
  610.       switch_to_buffer (create_buffer (get_input_from_stdin ()));
  611.     }
  612.  
  613.   // Force input to be echoed if not really interactive, but the user
  614.   // has forced interactive behavior.
  615.  
  616.   if (! interactive && (forced_interactive || really_forced_interactive))
  617.     {
  618.       rl_blink_matching_paren = 0;
  619.  
  620.       // XXX FIXME XXX -- is this the right thing to do?
  621.  
  622. #if ! defined (__EMX__)
  623.       bind_builtin_variable ("echo_executing_commands",
  624.                  (double) ECHO_CMD_LINE);
  625. #endif
  626.     }
  627.  
  628.   if (! (interactive || really_forced_interactive))
  629.     using_readline = 0;
  630.  
  631.   int retval = main_loop ();
  632.  
  633.   if (retval == 1 && ! error_state)
  634.     retval = 0;
  635.  
  636.   clean_up_and_exit (retval);
  637. }
  638.  
  639. /*
  640. ;;; Local Variables: ***
  641. ;;; mode: C++ ***
  642. ;;; End: ***
  643. */
  644.